package com.bjpowernode.pay.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bjpowernode.api.model.Recharge;
import com.bjpowernode.api.model.User;
import com.bjpowernode.api.serivce.RechargeService;
import com.bjpowernode.constants.Constant;
import com.bjpowernode.constants.RedisKey;
import com.bjpowernode.pay.util.HttpUtil;
import com.bjpowernode.pay.util.Pkipair;
import com.sun.org.apache.regexp.internal.RE;


import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.rmi.server.UID;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author 麦翔盛
 * @ClassName: RechargeService
 * @Package: com.bjpowernode.pay.service
 * @description: 快钱充值接口
 * @date 2022/5/30 22:51
 */
@Service
public class RechargeKuaiQianService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @DubboReference(interfaceClass = RechargeService.class, version = "1.0")
    private RechargeService rechargeService;

    /**
     * 生成新的订单
     *
     * @param uid           用户id
     * @param orderId       订单号
     * @param rechargeMoney 充值金额
     * @param channel       充值方式
     * @return 是否生成成功
     */
    public boolean generateNewOrder(Integer uid, String orderId, BigDecimal rechargeMoney, String channel) {
        Recharge recharge = new Recharge();
        recharge.setUid(uid);
        recharge.setRechargeNo(orderId);
        recharge.setRechargeStatus(Constant.RECHARGE_PROCESSING_0);
        recharge.setRechargeMoney(rechargeMoney);
        recharge.setRechargeTime(new Date());
        recharge.setRechargeDesc("盈利宝充值");
        recharge.setChannel(channel);

        int add = rechargeService.createNewRechargeOrder(recharge);
        return add > 0;
    }

    public Map<String, String> generateFormData(String phone, Integer uid, BigDecimal money) {
        Map<String, String> formData = new HashMap<>();

        //生成当前日期
        Date currentDate = new Date();

        //人民币网关账号，该账号为11位人民币网关商户编号+01,该参数必填。
        String merchantAcctId = "1001214035601";//
        //编码方式，1代表 UTF-8; 2 代表 GBK; 3代表 GB2312 默认为1,该参数必填。
        String inputCharset = "1";
        //接收支付结果的页面地址，该参数一般置为空即可。
        String pageUrl = "";
        //服务器接收支付结果的后台地址，该参数务必填写，不能为空。
        String bgUrl = "http://e5c3927727.zicp.vip/pay/notify/kq";
        //网关版本，固定值：v2.0,该参数必填。
        String version = "v2.0";
        //语言种类，1代表中文显示，2代表英文显示。默认为1,该参数必填。
        String language = "1";
        //签名类型,该值为4，代表PKI加密方式,该参数必填。
        String signType = "4";
        //支付人姓名,可以为空。
        String payerName = "";
        //支付人联系类型，1 代表电子邮件方式；2 代表手机联系方式。可以为空。
        String payerContactType = "2";
        //支付人联系方式，与payerContactType设置对应，payerContactType为1，则填写邮箱地址；payerContactType为2，则填写手机号码。可以为空。
        String payerContact = phone;
        //指定付款人，可以为空
        String payerIdType = "3";
        //付款人标识，可以为空
        String payerId = String.valueOf(uid);
        //付款人IP，可以为空
        String payerIP = "192.168.1.1";
        //终端ip，支持ipv4/6
        String terminalIp = "192.168.1.1";
        //平台名称
        String tdpformName = "盈利宝科技";
        //商户订单号，以下采用时间来定义订单号，商户可以根据自己订单号的定义规则来定义该值，不能为空。
        String orderId = "KQ" + generateOrderId(currentDate);

        //订单金额，金额以“分”为单位，商户测试以1分测试即可，切勿以大金额测试。该参数必填。
        //money传进来的是元 需要乘以100才是用分作为单位的金额
        //stripTrailingZeros()去掉小数点后面的数字
        //toPlainString()不使用科学计数法表示
        String orderAmount = money.multiply(new BigDecimal(100)).stripTrailingZeros().toPlainString();

        //订单提交时间，格式：yyyyMMddHHmmss，如：20071117020101，不能为空。
        String orderTime = new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(currentDate);
        //快钱时间戳，格式：yyyyMMddHHmmss，如：20071117020101， 可以为空
        String orderTimestamp = new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(currentDate);
        //商品名称，可以为空。
        String productName = "充值";
        //商品数量，可以为空。
        String productNum = "1";
        //商品代码，可以为空。
        String productId = "10000";
        //商品描述，可以为空。
        String productDesc = "盈利宝";
        //扩展字段1，商户可以传递自己需要的参数，支付完快钱会原值返回，可以为空。
        String ext1 = "扩展1";
        //扩展自段2，商户可以传递自己需要的参数，支付完快钱会原值返回，可以为空。
        String ext2 = "扩展2";
        //支付方式，一般为00，代表所有的支付方式。如果是银行直连商户，该值为10-1或10-2，必填。
        String payType = "00";
        //银行代码，如果payType为00，该值可以为空；如果payType为10-1或10-2，该值必须填写，具体请参考银行列表。
        String bankId = "";
        //同一订单禁止重复提交标志，实物购物车填1，虚拟产品用0。1代表只能提交一次，0代表在支付不成功情况下可以再提交。可为空。
        String redoFlag = "0";
        //快钱合作伙伴的帐户号，即商户编号，可为空。
        String pid = "";

        // signMsg 签名字符串 不可空，生成加密签名串
        String signMsgVal = "";
        signMsgVal = appendParam(signMsgVal, "inputCharset", inputCharset, formData);
        signMsgVal = appendParam(signMsgVal, "pageUrl", pageUrl, formData);
        signMsgVal = appendParam(signMsgVal, "bgUrl", bgUrl, formData);
        signMsgVal = appendParam(signMsgVal, "version", version, formData);
        signMsgVal = appendParam(signMsgVal, "language", language, formData);
        signMsgVal = appendParam(signMsgVal, "signType", signType, formData);
        signMsgVal = appendParam(signMsgVal, "merchantAcctId", merchantAcctId, formData);
        signMsgVal = appendParam(signMsgVal, "payerName", payerName, formData);
        signMsgVal = appendParam(signMsgVal, "payerContactType", payerContactType, formData);
        signMsgVal = appendParam(signMsgVal, "payerContact", payerContact, formData);
        signMsgVal = appendParam(signMsgVal, "payerIdType", payerIdType, formData);
        signMsgVal = appendParam(signMsgVal, "payerId", payerId, formData);
        signMsgVal = appendParam(signMsgVal, "payerIP", payerIP, formData);
        signMsgVal = appendParam(signMsgVal, "orderId", orderId, formData);
        signMsgVal = appendParam(signMsgVal, "orderAmount", orderAmount, formData);
        signMsgVal = appendParam(signMsgVal, "orderTime", orderTime, formData);
        signMsgVal = appendParam(signMsgVal, "orderTimestamp", orderTimestamp, formData);
        signMsgVal = appendParam(signMsgVal, "productName", productName, formData);
        signMsgVal = appendParam(signMsgVal, "productNum", productNum, formData);
        signMsgVal = appendParam(signMsgVal, "productId", productId, formData);
        signMsgVal = appendParam(signMsgVal, "productDesc", productDesc, formData);
        signMsgVal = appendParam(signMsgVal, "ext1", ext1, formData);
        signMsgVal = appendParam(signMsgVal, "ext2", ext2, formData);
        signMsgVal = appendParam(signMsgVal, "payType", payType, formData);
        signMsgVal = appendParam(signMsgVal, "bankId", bankId, formData);
        signMsgVal = appendParam(signMsgVal, "redoFlag", redoFlag, formData);
        signMsgVal = appendParam(signMsgVal, "pid", pid, formData);

        Pkipair pki = new Pkipair();
        String signMsg = pki.signMsg(signMsgVal);

        formData.put("signMsg", signMsg);
        formData.put("terminalIp", terminalIp);
        formData.put("tdpformName", tdpformName);
        return formData;
    }

    /**
     * 拼接参数 http://locahost:8080?k1=v1&k2=v2.....的形式
     *
     * @param returns
     * @param paramId
     * @param paramValue
     * @return
     */
    public String appendParam(String returns, String paramId, String paramValue, Map<String, String> formData) {
        if (returns != "") {
            if (paramValue != "" && paramValue != null) {

                returns += "&" + paramId + "=" + paramValue;
            }

        } else {

            if (paramValue != "" && paramValue != null) {
                returns = paramId + "=" + paramValue;
            }
        }

        if (formData != null) {
            formData.put(paramId, paramValue);
        }

        return returns;
    }

    /**
     * 生成订单编号
     * @param date 现在的时间
     * @return
     */
    public String generateOrderId(Date date) {
        //通过redis取出自增值，确保唯一
        String key = RedisKey.RECHARGE_ORDERID_INCR;
        long incr = stringRedisTemplate.boundValueOps(key).increment();

        return DateFormatUtils.format(date, "yyyyMMddHHmmssSSS") + String.valueOf(incr);
    }

    /**
     * 将订单保存到redis中
     *
     * @param orderId 订单编号
     */
    public boolean addToRedis(String orderId) {
        String key = RedisKey.RECHARGE_ORDERID_ZSET;
        return Boolean.TRUE.equals(stringRedisTemplate.boundZSetOps(RedisKey.RECHARGE_ORDERID_ZSET)
                .add(orderId, System.currentTimeMillis()));
    }

    /**
     * 接受异步通知请求
     *
     * @param request 请求
     */
    public void handlerNotify(HttpServletRequest request) {
        String merchantAcctId = request.getParameter("merchantAcctId");
        String version = request.getParameter("version");
        String language = request.getParameter("language");
        String signType = request.getParameter("signType");
        String payType = request.getParameter("payType");
        String bankId = request.getParameter("bankId");
        String orderId = request.getParameter("orderId");
        String orderTime = request.getParameter("orderTime");
        String orderAmount = request.getParameter("orderAmount");
        String bindCard = request.getParameter("bindCard");
        if (request.getParameter("bindCard") != null) {
            bindCard = request.getParameter("bindCard");
        }
        String bindMobile = "";
        if (request.getParameter("bindMobile") != null) {
            bindMobile = request.getParameter("bindMobile");
        }
        String bankDealId = request.getParameter("bankDealId");
        String dealTime = request.getParameter("dealTime");
        String payAmount = request.getParameter("payAmount");
        String fee = request.getParameter("fee");
        String ext1 = request.getParameter("ext1");
        String ext2 = request.getParameter("ext2");
        String payResult = request.getParameter("payResult");
        String aggregatePay = request.getParameter("aggregatePay");
        String errCode = request.getParameter("errCode");
        String dealId = request.getParameter("dealId");
        String signMsg = request.getParameter("signMsg");
        String merchantSignMsgVal = "";
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "merchantAcctId", merchantAcctId, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "version", version, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "language", language, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "signType", signType, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "payType", payType, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "bankId", bankId, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "orderId", orderId, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "orderTime", orderTime, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "orderAmount", orderAmount, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "bindCard", bindCard, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "bindMobile", bindMobile, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "dealId", dealId, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "bankDealId", bankDealId, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "dealTime", dealTime, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "payAmount", payAmount, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "fee", fee, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "ext1", ext1, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "ext2", ext2, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "payResult", payResult, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "aggregatePay", aggregatePay, null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "errCode", errCode, null);
        System.out.println("merchantSignMsgVal=" + merchantSignMsgVal);
        Pkipair pki = new Pkipair();
        //验证签名
        boolean flag = pki.enCodeByCer(merchantSignMsgVal, signMsg);

        //因为模拟测试无法真正验签 所以先通过
        flag = true;

        if (flag) {
            //判断merchantAcctId是不是商家自己的
            if ("1001214035601".equals(merchantAcctId)) {
                //异步通知 订单结果
                rechargeService.doRechargeHandler(orderId, payAmount, payResult);
                System.out.println(orderId + "订单处理充值业务");
            } else {
                //打印日志
                System.out.println("订单号" + orderId + "不是商家的，商家号是" + merchantAcctId);
            }
        } else {
            System.out.println("签名错误请检查");
        }
        //删除已经处理过的订单
        stringRedisTemplate.boundZSetOps(RedisKey.RECHARGE_ORDERID_ZSET).remove(orderId);
    }

    /**
     * 接受快钱对账的请求
     */
    public void handerKuaiQianQuery() {
        //从redis中取出未处理的订单
        Set<String> rechargeSet = stringRedisTemplate.boundZSetOps(RedisKey.RECHARGE_ORDERID_ZSET).range(0, -1);
        for (String orderId : rechargeSet) {
            //处理这个订单
            invokeKuaiqianApi(orderId);
            //处理完这个订单后在缓存中删除这个订单
            stringRedisTemplate.boundZSetOps(RedisKey.RECHARGE_ORDERID_ZSET).remove(orderId);
        }
        System.out.println(new Date() + "时间前的订单处理完成，20分钟后继续处理下一批订单");
    }

    public void invokeKuaiqianApi(String orderId){
        Map<String, Object> request = new HashMap<String, Object>();
        //固定值：1代表UTF-8;
        String inputCharset = "1";
        //固定值：v2.0 必填
        String version = "v2.0";
        //1代表Md5，2 代表PKI加密方式  必填
        String signType = "2";
        //人民币账号 membcode+01  必填
        String merchantAcctId = "1001214035601";//1001293267101（XIXMFISFG7RGDKQN） 1001217486601(5B5EQDQH2X7ERM9A)
        //固定值：0 按商户订单号单笔查询，1 按交易结束时间批量查询必填
        String queryType = "0";
        //固定值：1	代表简单查询 必填
        String queryMode = "1";

        String key = "27YKWKBKHT2IZSQ4";

        request.put("inputCharset", inputCharset);
        request.put("version", version);
        request.put("signType", signType);
        request.put("merchantAcctId", merchantAcctId);
        request.put("queryType", queryType);
        request.put("queryMode", queryMode);

        request.put("orderId", orderId);

        String message="";
        message = appendParam(message,"inputCharset",inputCharset,null);
        message = appendParam(message,"version",version,null);
        message = appendParam(message,"signType",signType,null);
        message = appendParam(message,"merchantAcctId",merchantAcctId,null);
        message = appendParam(message,"queryType",queryType,null);
        message = appendParam(message,"queryMode",queryMode,null);
        message = appendParam(message,"orderId",orderId,null);
         message = appendParam(message,"key",key,null);


        Pkipair pki = new Pkipair();
        String sign = pki.signMsg(message);

         request.put("signMsg", sign);

        //sandbox提交地址
        String reqUrl = "https://sandbox.99bill.com/gatewayapi/gatewayOrderQuery.do";

        String response = "";

        try {
            response = HttpUtil.doPostJsonRequestByHttps(JSON.toJSONString(request), reqUrl, 3000, 8000);
            System.out.println("快钱支付结果"+response);
            //解析json，获得订单号，订单状态，订单金额
            JSONObject jsonObject = JSONObject.parseObject(response);
            //判断这个订单是否存在
            if (jsonObject.get("orderDetail") != null){
                //获取订单详情
                JSONObject orderDetail = jsonObject.getJSONArray("orderDetail").getJSONObject(0);
                String payAmount = orderDetail.getString("payAmount");
                String payResult = orderDetail.getString("payResult");
                //异步通知 处理订单结果
                rechargeService.doRechargeHandler(orderId,payAmount,payResult);
            }

        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
    }
}
